/**
 * @file TimeIntergratorFactory.h
 * @brief The factory patter to build TimeIntergrator.
 * @author XDDDD
 * @version 
 * @date 2021-04-28
 */

#ifndef __PAISLEYPARK__TIMEINTERGRATORFACTORY_H__
#define __PAISLEYPARK__TIMEINTERGRATORFACTORY_H__

#include "TimeIntergrator.h"
#include <map>
#include <cstring>

template <std::size_t DIM>
class TimeIntergratorFactory {
public:
	typedef TimeIntergrator<DIM>* (*CreateTimeIngergratorCallback)(const std::size_t _p);
private:
	typedef std::map<std::string , CreateTimeIngergratorCallback> CallbackMp;
public:
	/**
	 * @brief Register the TimeIntergrator method.
	 *
	 * @param _MethodId The Id of the method. 
	 * @param _createFn The function point of the constructor of the method.
	 *
	 * @return true if registered.
	 */
	bool RegisterMethod(const std::string _MethodId, CreateTimeIngergratorCallback _createFn);
	/**
	 * @brief Unregister the TimeIntergrator method.
	 *
	 * @param _MethodId The Id of the method.
	 *
	 * @return true if unregistered.
	 */
	bool UnregisterMethod(const std::string _MethodId);
	/**
	 * @brief Create the method.
	 *
	 * @param _MethodId The Id of the method.
	 * @param _p The given order of accuracy.
	 *
	 * @return Point of the method.
	 */
	TimeIntergrator<DIM>* CreateMethod(const std::string _MethodId, const std::size_t _p);
	/**
	 * @brief Create the method.
	 *
	 * @param _MethodId The Id of the method.
	 *
	 * @return Point of the method.
	 */
	TimeIntergrator<DIM>* CreateMethod(const std::string _MethodId);
	/**
	 * @brief Destructor.
	 */
	~TimeIntergratorFactory(){};
	/**
	 * @brief The interface to use this singelton factory.
	 *
	 * @return point of this
	 */
	static TimeIntergratorFactory<DIM>* Instance() {
		if(!__obj) {
			__obj = new TimeIntergratorFactory<DIM>;
		}
		return __obj;
	};
private:
	static TimeIntergratorFactory<DIM>* __obj;
	/**
	 * @brief Store the methodId and its create function.
	 */
	CallbackMp __callbacks;
	/**
	 * @brief Constructor, this is a singelton so the constructor is private.
	 */
	TimeIntergratorFactory(){};
};


template <std::size_t DIM>
TimeIntergratorFactory<DIM>* TimeIntergratorFactory<DIM>::__obj = 0;

template <std::size_t DIM>
bool TimeIntergratorFactory<DIM>::RegisterMethod(const std::string _MethodId, CreateTimeIngergratorCallback _createFn) {
	return __callbacks.insert(typename CallbackMp::value_type(_MethodId, _createFn)).second;
};

template <std::size_t DIM>
bool TimeIntergratorFactory<DIM>::UnregisterMethod(const std::string _MethodId) {
	return __callbacks.erase(_MethodId) == 1;
};

template <std::size_t DIM>
TimeIntergrator<DIM>* TimeIntergratorFactory<DIM>::CreateMethod(const std::string _MethodId, const std::size_t _p) {
	typename CallbackMp::const_iterator i = __callbacks.find(_MethodId);
	if(i == __callbacks.end()) {
		std::cerr << "Unknown Method Id." << std::endl;
		std::exit(-1);
	}
	return (i->second)(_p);
}

template <std::size_t DIM>
TimeIntergrator<DIM>* TimeIntergratorFactory<DIM>::CreateMethod(const std::string _MethodId) {
	typename CallbackMp::const_iterator i = __callbacks.find(_MethodId);
	if(i == __callbacks.end()) {
		std::cerr << "Unknown Method Id." << std::endl;
		std::exit(-1);
	}
	return (i->second)(1);
}

#else
//Do nothing.
#endif
